package com.tools.web.http;

import com.tools.common.container.OwnPairs;
import com.tools.common.container.OwnRows;
import com.tools.common.object.Note;
import org.apache.http.client.config.RequestConfig;

import java.net.URL;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;

/**
 * HTTP 请求构造对象
 * 里面包装了发送 HTTP
 * 请求常用的参数配置项
 * */
@Note("HTTP 请求构造对象，里面包装了发送 HTTP 请求常用的参数配置项")
public final class HttpBuilder extends HttpBuildEntity {

    @Note("如果使用链式方式构造 HttpBuilder 实例，此属性可用于链式方式设置请求配置")
    private volatile RequestConfig.Builder tempRequestConfigBuilder;

    /* **************************************************************************************
     *
     *          构造实例
     *
     * **************************************************************************************
     * */

    public HttpBuilder(String url) {
        super(url);
    }

    public HttpBuilder(URL url) {
        super(url);
    }

    public static HttpBuilder of(String url) {
        return new HttpBuilder(url);
    }

    public static HttpBuilder of(URL url) {
        return new HttpBuilder(url);
    }

    /* **************************************************************************************
     *
     *          链式方法
     *
     * **************************************************************************************
     * */

    public HttpBuilder url(String url) {
        this.setUrl(url);
        return this;
    }

    public HttpBuilder url(URL url) {
        this.setUrl(url);
        return this;
    }


    public HttpBuilder connectTimeout(int timeout) {
        private_lazyInitRequestConfig();
        this.tempRequestConfigBuilder.setConnectTimeout(timeout);
        return this;
    }

    public HttpBuilder connectionRequestTimeout(int timeout) {
        private_lazyInitRequestConfig();
        this.tempRequestConfigBuilder.setConnectionRequestTimeout(timeout);
        return this;
    }

    public HttpBuilder socketTimeout(int timeout) {
        private_lazyInitRequestConfig();
        this.tempRequestConfigBuilder.setSocketTimeout(timeout);
        return this;
    }

    public HttpBuilder redirectsEnabled(boolean redirectsEnabled) {
        private_lazyInitRequestConfig();
        this.tempRequestConfigBuilder.setRedirectsEnabled(redirectsEnabled);
        return this;
    }

    public HttpBuilder requestConfig(RequestConfig requestConfig) {
        if(requestConfig != null) this.tempRequestConfigBuilder = null;
        this.setRequestConfig(requestConfig);
        return this;
    }

    public HttpBuilder async(boolean isAsync) {
        this.setAsync(isAsync);
        return this;
    }

    public HttpBuilder asyncCallback(HttpAsyncCallback callback) {
        this.setAsyncCallback(callback);
        return this;
    }

    public HttpBuilder printLog(boolean logPrint) {
        this.setPrintLog(logPrint);
        return this;
    }

    public HttpResult executeGet() {
        private_buildRequestConfig();
        return HttpKit.sendGet(this);
    }

    public HttpResult executePost() {
        private_buildRequestConfig();
        return HttpKit.sendPost(this);
    }

    public HttpResult executePut() {
        private_buildRequestConfig();
        return HttpKit.sendPut(this);
    }

    public HttpResult executeDelete() {
        private_buildRequestConfig();
        return HttpKit.sendDelete(this);
    }

    @Override
    public String toString() {
        return "HttpBuilder{" +
                "async=" + async +
                ", printLog=" + printLog +
                ", url='" + url + '\'' +
                ", asyncCallback=" + asyncCallback +
                ",\n requestConfig=" + requestConfig +
                ",\n tempRequestConfigBuilder=" + tempRequestConfigBuilder +
                ",\n headers=" + headers +
                ",\n parameters=" + parameters +
                ",\n uploadFiles=" + uploadFiles +
                ",\n httpResult=" + httpResult +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        HttpBuilder that = (HttpBuilder) o;
        return Objects.equals(url, that.url);
    }

    @Override
    public int hashCode() {
        return Objects.hash(url);
    }

    /* **************************************************************************************
     *
     *          参数操作的链式方法
     *
     * **************************************************************************************
     * */

    
    public HttpBuilder param(String name, Object value) {
        super.protected_param(name, value);
        return this;
    }

    
    public HttpBuilder params(Map parameters) {
        super.protected_params(parameters);
        return this;
    }

    
    public HttpBuilder params(OwnPairs parameters) {
        super.protected_params(parameters);
        return this;
    }

    
    public HttpBuilder params(Object javaBean) {
        super.protected_params(javaBean);
        return this;
    }

    
    public HttpBuilder params(String jsonObject) {
        super.protected_params(jsonObject);
        return this;
    }

    
    public HttpBuilder clearParams() {
        super.protected_clearParams();
        return this;
    }

    
    public HttpBuilder removeParam(String name) {
        super.protected_removeParam(name);
        return this;
    }

    
    public HttpBuilder removeParams(String... names) {
        super.protected_removeParams(names);
        return this;
    }

    
    public HttpBuilder removeParams(Iterable<String> names) {
        super.protected_removeParams(names);
        return this;
    }

    /* **************************************************************************************
     *
     *          请求头操作的链式方法
     *
     * **************************************************************************************
     * */

    public HttpBuilder header(String name, String value) {
        super.protected_header(name, value);
        return this;
    }

    public HttpBuilder headers(Map headers) {
        super.protected_headers(headers);
        return this;
    }

    public HttpBuilder headers(OwnPairs headers) {
        super.protected_headers(headers);
        return this;
    }

    public HttpBuilder clear() {
        super.protected_clearHeaders();
        return this;
    }

    public HttpBuilder removeHeader(String name) {
        super.protected_removeHeader(name);
        return this;
    }

    public HttpBuilder removeHeader(String... names) {
        super.protected_removeHeaders(names);
        return this;
    }

    public HttpBuilder removeHeader(Iterable<String> names) {
        super.protected_removeHeaders(names);
        return this;
    }

    /* **************************************************************************************
     *
     *          文件集合操作的链式方法
     *
     * **************************************************************************************
     * */

    public HttpBuilder addFile(UploadFile uploadFile) {
        super.protected_addFile(uploadFile);
        return this;
    }

    public HttpBuilder addFiles(UploadFile... uploadFiles) {
        super.protected_addFiles(uploadFiles);
        return this;
    }

    public HttpBuilder addFiles(Collection<UploadFile> uploadFiles) {
        super.protected_addFiles(uploadFiles);
        return this;
    }

    public HttpBuilder addFiles(OwnRows<UploadFile> uploadFiles) {
        super.protected_addFiles(uploadFiles);
        return this;
    }

    public HttpBuilder removeFile(String uploadKey) {
        super.protected_removeFile(uploadKey);
        return this;
    }


    public HttpBuilder removeFiles(String... uploadKeys) {
        super.protected_removeFiles(uploadKeys);
        return this;
    }

    public HttpBuilder removeFiles(Iterable<String> uploadKeys) {
        super.protected_removeFiles(uploadKeys);
        return this;
    }

    /* **************************************************************************************
     *
     *          私有逻辑
     *
     * **************************************************************************************
     * */

    @Note("（非线程安全）懒加载 RequestConfig.Builder 对象，用于链式设置 RequestConfig 的各项参数")
    private void private_lazyInitRequestConfig() {
        if(tempRequestConfigBuilder != null) return;
        this.tempRequestConfigBuilder = RequestConfig.custom();
    }


    @Note("根据选项设置 RequestConfig 对象")
    private void private_buildRequestConfig() {
        if(requestConfig != null || tempRequestConfigBuilder == null) return;
        this.requestConfig = this.tempRequestConfigBuilder.build();
        this.tempRequestConfigBuilder = null;
    }

    
}
